import { SegmentationRepresentations } from '../../enums';

import { getSegmentIndexColor } from '../../stateManagement/segmentation/config/segmentationColor';
import { getActiveSegmentation } from '../../stateManagement/segmentation/getActiveSegmentation';
import { getActiveSegmentIndex } from '../../stateManagement/segmentation/getActiveSegmentIndex';
import { getSegmentationRepresentationVisibility } from '../../stateManagement/segmentation/getSegmentationRepresentationVisibility';
import { internalGetHiddenSegmentIndices } from '../../stateManagement/segmentation/helpers/internalGetHiddenSegmentIndices';
import { segmentationStyle } from '../../stateManagement/segmentation/SegmentationStyle';
import type { ContourStyle } from '../../types';

export interface SVGStyleForSegmentParams {
  segmentationId: string;
  segmentIndex: number;
  viewportId: string;
  autoGenerated?: boolean;
}

/**
 * Gets the SVG style properties for a segmentation segment based on its state and configuration.
 * It is used for tools that draw svg and want to match the style of the segmentation.
 *
 * The style is determined by merging configurations from different levels based on precedence:
 * - Global segmentation style
 * - Per-segmentation style
 * - Per-segment style
 *
 * The style properties include:
 * - Line width, dash pattern, and opacity
 * - Fill opacity
 * - Colors for outline and fill
 * - Visibility
 *
 * The style varies based on whether the segment is:
 * - Auto-generated
 * - Active/inactive
 * - Currently being hovered/selected
 *
 * @param params - The parameters for getting the segment style
 * @param params.segmentationId - The ID of the segmentation
 * @param params.segmentIndex - The index of the segment within the segmentation
 * @param params.viewportId - The ID of the viewport
 * @param params.autoGenerated - Whether the segment was auto-generated
 * @returns The SVG style properties for the segment
 */
export function getSVGStyleForSegment({
  segmentationId,
  segmentIndex,
  viewportId,
  autoGenerated = false,
}: SVGStyleForSegmentParams) {
  const segmentColor = getSegmentIndexColor(
    viewportId,
    segmentationId,
    segmentIndex
  );

  const segmentationVisible = getSegmentationRepresentationVisibility(
    viewportId,
    {
      segmentationId,
      type: SegmentationRepresentations.Contour,
    }
  );

  const activeSegmentation = getActiveSegmentation(viewportId);
  const isActive = activeSegmentation?.segmentationId === segmentationId;

  const inactiveSegmentationVisibility =
    segmentationStyle.getRenderInactiveSegmentations(viewportId);

  // Merge the configurations from different levels based on its precedence
  const style = segmentationStyle.getStyle({
    viewportId,
    segmentationId,
    type: SegmentationRepresentations.Contour,
    segmentIndex,
  });

  const mergedConfig = style as ContourStyle;
  let lineWidth = 1;
  let lineDash = undefined;
  let lineOpacity = 1;
  let fillOpacity = 0;
  let renderFill = mergedConfig.renderFill ?? true;
  let renderOutline = mergedConfig.renderOutline ?? true;

  if (autoGenerated) {
    lineWidth = mergedConfig.outlineWidthAutoGenerated ?? lineWidth;
    lineDash = mergedConfig.outlineDashAutoGenerated ?? lineDash;
    lineOpacity = mergedConfig.outlineOpacity ?? lineOpacity;
    fillOpacity = mergedConfig.fillAlphaAutoGenerated ?? fillOpacity;
  } else if (isActive) {
    lineWidth = mergedConfig.outlineWidth ?? lineWidth;
    lineDash = mergedConfig.outlineDash ?? lineDash;
    lineOpacity = mergedConfig.outlineOpacity ?? lineOpacity;
    fillOpacity = mergedConfig.fillAlpha ?? fillOpacity;
  } else {
    lineWidth = mergedConfig.outlineWidthInactive ?? lineWidth;
    lineDash = mergedConfig.outlineDashInactive ?? lineDash;
    lineOpacity = mergedConfig.outlineOpacityInactive ?? lineOpacity;
    fillOpacity = mergedConfig.fillAlphaInactive ?? fillOpacity;
    renderFill = mergedConfig.renderFillInactive ?? renderFill;
    renderOutline = mergedConfig.renderOutlineInactive ?? renderOutline;
  }

  // Change the line thickness when the mouse is over the contour segment
  if (getActiveSegmentIndex(segmentationId) === segmentIndex) {
    lineWidth += mergedConfig.activeSegmentOutlineWidthDelta;
  }

  lineWidth = renderOutline ? lineWidth : 0;
  fillOpacity = renderFill ? fillOpacity : 0;
  const color = `rgba(${segmentColor[0]}, ${segmentColor[1]}, ${segmentColor[2]}, ${lineOpacity})`;
  const fillColor = `rgb(${segmentColor[0]}, ${segmentColor[1]}, ${segmentColor[2]})`;

  const hiddenSegments = internalGetHiddenSegmentIndices(viewportId, {
    segmentationId,
    type: SegmentationRepresentations.Contour,
  });

  const isVisible = !hiddenSegments.has(segmentIndex);

  return {
    color,
    fillColor,
    lineWidth,
    fillOpacity,
    lineDash,
    textbox: {
      color,
    },
    visibility: isActive
      ? segmentationVisible && isVisible
      : inactiveSegmentationVisibility,
  };
}
